package com.atguigu.myssm.io;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class ClassPathXmlApplicationContext implements BeanFactory{
    private Map<String,Object> beanMap = new HashMap<>();
    public ClassPathXmlApplicationContext() {
        try {
            InputStream stream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = null;
            documentBuilder = builderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(stream);
            NodeList nodeList = document.getElementsByTagName("bean");
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) node;
                    String id = element.getAttribute("id");
                    String className = element.getAttribute("class");
                    Object beanObj = Class.forName(className).newInstance();
                    beanMap.put(id, beanObj);
                }
            }
            for(int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if(node.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) node;
                    String id = element.getAttribute("id");
                    NodeList childNodes = element.getChildNodes();
                    for(int j = 0; j < childNodes.getLength(); j++) {
                        Node item = childNodes.item(j);
                        if(item.getNodeType()==Node.ELEMENT_NODE && "property".equals(item.getNodeName())) {
                            Element propertyElement = (Element) item;
                            String name = propertyElement.getAttribute("name");
                            String ref = propertyElement.getAttribute("ref");
                            Object refObj = beanMap.get(ref);
                            Object idObj = beanMap.get(id);
                            Class idObjClass = idObj.getClass();
                            Field declaredField = idObjClass.getDeclaredField(name);
                            declaredField.setAccessible(true);
                            declaredField.set(idObj,refObj);
                        }
                    }
                }
            }
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public Object getBean(String id) {
        return beanMap.get(id);
    }
}
